﻿using Caviar.Core.Interface;
using Caviar.SharedKernel.Common.Extensions;
using Caviar.SharedKernel.Common.Helpers;
using Caviar.SharedKernel.Entities;
using Caviar.SharedKernel.Entities.IM;
using Caviar.SharedKernel.Template.View.IM;
using Caviar.SharedKernel.Template.View.IM.Friends;
using Caviar.SharedKernel.Template.View.IM.Messages;
using Masuit.Tools.Security;
using Masuit.Tools.Systems;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.IdentityModel.Tokens;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using static Caviar.Core.Services.IMServices.IMUserManager;

namespace Caviar.Core.Services.IMServices
{
    public class IMServices : DbServices
    {
        private readonly IAppDbContext _appDbContext;
        private readonly IMUserManager  _imUserManager;
        private readonly IDatabase _redis;
        public IMServices(
            IAppDbContext dbContext,
            IMUserManager imUserManager,
            RedisHelper client) : base(dbContext)
        {
            _appDbContext = dbContext;
            _imUserManager = imUserManager;
            _redis = client.GetDatabase();

            #region 数据生成
            GenerateTopicSeedData();
            #endregion
        }

        /// <summary>
        /// 注册聊天账号
        /// </summary>
        /// <returns></returns>
        public async Task<bool> RegisterAsync(RegisterModel model)
        {
            if (model == null)
                throw new Exception("数据不能为空");
            if (model.NickName == null)
                throw new Exception("昵称不能为空");
            if (model.UserName == null)
                throw new Exception("用户名不能为空");
            if (model.Password == null)
                throw new Exception("密码不能为空");
            if (model.Password != model.ConfirmPassword)
                throw new Exception("两次密码不一致");

            var user = await _appDbContext.DbContext.Set<User>().SingleOrDefaultAsync(x => x.UserName == model.UserName);
            if (user != null)
                throw new Exception("注册失败，用户名已存在");

            var clientId = Guid.NewGuid().ToString();
            var userTopics = new List<UserTopic>();
            var topics = await _appDbContext.DbContext.Set<Topic>().Where(x => x.IsDefault == true).ToListAsync();
            foreach (var topic in topics)
            {
                UserTopic userTopic = new()
                {
                    TopicId = topic.Id,
                    Subscribe = topic.SubscribeFormat,
                    Publish = topic.PublishFormat,
                    IsUnsubscribe = false,
                    IsUnpublish = false
                };
                userTopic.CreateSubscribeOrPublishTitle(clientId);
                userTopics.Add(userTopic);
            }

           var avatar = new string[]
           {
                "https://tse1-mm.cn.bing.net/th/id/OIP-C.BxRQRIy3nCLc5rQEwDW8YAHaKe?w=156&h=220&c=7&r=0&o=5&dpr=1.5&pid=1.7",
                "https://tse2-mm.cn.bing.net/th/id/OIP-C.-h3Dmh2C1gRdSxdhhqmN3AHaHa?w=220&h=220&c=7&r=0&o=5&dpr=1.5&pid=1.7",
                "https://tse4-mm.cn.bing.net/th/id/OIP-C.tfAOG3BFaoT93euAsaw8VAHaHa?w=172&h=180&c=7&r=0&o=5&dpr=1.5&pid=1.7",
                "https://tse1-mm.cn.bing.net/th/id/OIP-C.ljg5diYqUqFJ7DUAYS_TDQAAAA?w=180&h=180&c=7&r=0&o=5&dpr=1.5&pid=1.7",
                "https://tse1-mm.cn.bing.net/th/id/R-C.3276b85c61043b2ec23911407b2c3a1a?rik=mDOWv%2bnoHdIcMQ&riu=http%3a%2f%2ftupian.qqw21.com%2farticle%2fUploadPic%2f2012-12%2f2012124101725504.jpg&ehk=M0MaXInAwy5pEIfXoYzJlBP0BOJ8iHuLlu7WnRUReY8%3d&risl=&pid=ImgRaw&r=0"
           };

            Random ran = new Random();
            await _appDbContext.DbContext.Set<User>().AddAsync(new User
            {
                UserName = model.UserName,
                NickName = model.NickName,
                Password = model.Password.MDString(),
                ClientId = clientId,
                IsActive = false,
                Topics = userTopics,
                Avatar = avatar[ran.Next(0, 5)],
                Birthday = DateTime.Now
            });

            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <returns></returns>
        public async Task<string> LoginAsync(string userName, string password)
        {
            if (userName == null || password == null)
            {
                throw new Exception("用户名或密码不能为空");
            }

            var user = await _appDbContext.DbContext.Set<User>().SingleOrDefaultAsync(x => x.UserName == userName);
            if (user == null)
            {
                throw new Exception("用户名或密码错误");
            }
            if (user.Password != password.MDString())
            {
                throw new Exception("用户名或密码错误");
            }

            DateTime dateTime = DateTime.Now;
            var token = _imUserManager.Create(new[]
            {
                 new Claim(ClaimAttributes.UserId, user.Id.ToString()),
                 new Claim(ClaimAttributes.UserName, user.UserName),
                 new Claim(ClaimAttributes.ClientId, user.ClientId),
                 new Claim(ClaimAttributes.UserNickName, user.NickName),
                 new Claim(ClaimAttributes.Avatar, user.Avatar)
            }, dateTime);

            user.Token = token;
            user.LastLoginTime = user.LoginTime ?? null;
            user.LoginTime = dateTime;
            user.IsOnline = true;
            user.UpdateTime = dateTime;

            var entity = _appDbContext.DbContext.Set<User>().Update(user);

            if ((await _appDbContext.DbContext.SaveChangesAsync()) == 0)
            {
                throw new Exception("登录失败，请联系管理员");
            }
            await _imUserManager.SaveAsync(token, user, dateTime);
            return token;
        }

        /// <summary>
        /// 添加好友
        /// </summary>
        /// <returns></returns>
        public async Task<bool> AddFriendByUserNameAsync(string userName, string messages)
        {
            if (userName.IsNullOrEmpty())
                throw new Exception("账号不能为空");

            var user = await _imUserManager.GetCurrentUserAsync();
            if (userName == user.UserName)
                throw new Exception("不允许添加自己为好友");

            var anotherUser = await _appDbContext.DbContext.Set<User>().SingleOrDefaultAsync(x => x.UserName == userName);
            if (anotherUser == null)
                throw new Exception("账号不存在");

            bool isReapply = false;
            List<Friend> friends = new List<Friend>();
            var friend = await _appDbContext.DbContext.Set<Friend>().SingleOrDefaultAsync(x => x.UserId == user.Id && x.AnotherId == anotherUser.Id);
            switch (friend?.StatusType)
            {
                case FriendStatusType.InitiateFriendRequest:
                    break;
                case FriendStatusType.ReceiveFriendRequest:
                    throw new Exception("对方已发出添加您为好友的邀请信息，请前去处理");
                case FriendStatusType.WaitingForAgree:
                    throw new Exception("已发出添加对方为好友的邀请信息，请耐心等待对方回应");
                case FriendStatusType.Agree:
                    throw new Exception("对方已是你好友");
                case FriendStatusType.Agreed:
                    throw new Exception("对方已是你好友");
                case FriendStatusType.Reject:
                    isReapply = true;
                    break;
                case FriendStatusType.Rejected:
                    isReapply = true;
                    break;
                case FriendStatusType.Cancell:
                    isReapply = true;
                    break;
                case FriendStatusType.Cancelled:
                    isReapply = true;
                    break;
                case FriendStatusType.Ignore:
                    isReapply = true;
                    break;
                case FriendStatusType.Ignored:
                    isReapply = true;
                    break;
                case FriendStatusType.Shield:
                    throw new Exception("你已把对方屏蔽");
                case FriendStatusType.Shielded:
                    throw new Exception("你已被对方屏蔽");
                case FriendStatusType.InBlacklist:
                    throw new Exception("对方已在你的黑名单列表中");
                case FriendStatusType.InBlacklisted:
                    throw new Exception("你已被对方拉入黑名单");
            }
            if (isReapply == true) 
            {
                var anotherFriend = await _appDbContext.DbContext.Set<Friend>().SingleOrDefaultAsync(x => x.UserId == user.Id && x.AnotherId == anotherUser.Id);
                anotherFriend.StatusType = FriendStatusType.ReceiveFriendRequest;
                friend.StatusType = FriendStatusType.WaitingForAgree;
                friends.Add(friend);
                friends.Add(anotherFriend);
                _appDbContext.DbContext.Set<Friend>().UpdateRange(friends);
            }
            else 
            {
                var sf = SnowFlake.GetInstance();
                var friendToken = sf.GetUniqueShortId(36);
                List<UserTopic> ownUserTopics = new List<UserTopic>();
                List<UserTopic> friendUserTopics = new List<UserTopic>();

                var topics = await _appDbContext.DbContext.Set<Topic>().Where(x => x.IsDefault == false).ToListAsync();
                foreach (var topic in topics)
                {
                    UserTopic ownUserTopic = new()
                    {
                        UserId = user.Id,
                        TopicId = topic.Id,
                        Subscribe = topic.SubscribeFormat,
                        Publish = topic.PublishFormat,
                        IsUnsubscribe = true,
                        IsUnpublish = true
                    };
                    ownUserTopic.CreateSubscribeOrPublishTitle(user.ClientId, anotherUser.ClientId, true);
                    ownUserTopics.Add(ownUserTopic);

                    UserTopic friendUserTopic = new()
                    {
                        UserId = anotherUser.Id,
                        TopicId = topic.Id,
                        Subscribe = topic.SubscribeFormat,
                        Publish = topic.PublishFormat,
                        IsUnsubscribe = true,
                        IsUnpublish = true
                    };
                    friendUserTopic.CreateSubscribeOrPublishTitle(anotherUser.ClientId, user.ClientId, true);
                    friendUserTopics.Add(friendUserTopic);
                }

                var ownFriend = new Friend
                {
                    UserId = user.Id,
                    AnotherId = anotherUser.Id,
                    Token = friendToken,
                    Remarks = anotherUser.NickName,
                    IsUnasked = true,
                    StatusType = FriendStatusType.WaitingForAgree,
                    AddFriendTime = DateTime.Now,
                    ContactTopics = ownUserTopics,
                    Remark = messages
                };

                var anotherFriend = new Friend
                {
                    UserId = anotherUser.Id,
                    AnotherId = user.Id,
                    Token = friendToken,
                    Remarks = user.NickName,
                    IsUnasked = false,
                    StatusType = FriendStatusType.ReceiveFriendRequest,
                    ContactTopics = friendUserTopics,
                    Remark = messages
                };

                friends.Add(ownFriend);
                friends.Add(anotherFriend);
                await _appDbContext.DbContext.Set<Friend>().AddRangeAsync(friends);
            }

            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 通知列表
        /// </summary>
        /// <param name="search"></param>
        /// <returns></returns>
        public async Task<List<NotifyModel>> NotifyAsync(string search) 
        {
            return await _appDbContext.DbContext.Set<Friend>()
                   .Where(x => x.UserId == _imUserManager.GetCurrentUserId() && x.StatusType == FriendStatusType.ReceiveFriendRequest)
                   .Select(x => new NotifyModel
                   {
                       Id = x.Id,
                       Type = Convert.ToInt32(x.StatusType),
                       Title = x.Another.UserName,
                       Description = x.Remark
                   }).ToListAsync();
        }

        /// <summary>
        /// 处理好友请求
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public async Task<bool> HandleFriendRequestAsync(string userName, FriendStatusType status)
        {
            if (userName.IsNullOrEmpty())
                throw new Exception("账号不能为空");

            var user = await _imUserManager.GetCurrentUserAsync();
            if (userName == user.UserName)
                throw new Exception("不允许添加自己为好友");

            var anotherUser = await _appDbContext.DbContext.Set<User>().SingleOrDefaultAsync(x => x.UserName == userName);
            if (anotherUser == null)
                throw new Exception("账号不存在");

            var ownFriend = await _appDbContext.DbContext.Set<Friend>().SingleOrDefaultAsync(x => x.UserId == user.Id && x.AnotherId == anotherUser.Id && x.StatusType == FriendStatusType.ReceiveFriendRequest);
            var anotherFriend = await _appDbContext.DbContext.Set<Friend>().SingleOrDefaultAsync(x => x.UserId == anotherUser.Id && x.AnotherId == user.Id && x.StatusType == FriendStatusType.WaitingForAgree);

            if (ownFriend == null || anotherFriend == null)
                throw new Exception("不存在的邀请信息");

            List<Friend> friends = new List<Friend>();

            switch (status)
            {
                case FriendStatusType.InitiateFriendRequest:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.ReceiveFriendRequest:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.WaitingForAgree:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.Agree:
                    ownFriend.StatusType = FriendStatusType.Agree;
                    anotherFriend.StatusType = FriendStatusType.Agreed;
                    break;
                case FriendStatusType.Agreed:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.Reject:
                    ownFriend.StatusType = FriendStatusType.Reject;
                    anotherFriend.StatusType = FriendStatusType.Rejected;
                    break;
                case FriendStatusType.Rejected:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.Cancell:
                    ownFriend.StatusType = FriendStatusType.Cancell;
                    anotherFriend.StatusType = FriendStatusType.Cancelled;
                    break;
                case FriendStatusType.Cancelled:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.Ignore:
                    ownFriend.StatusType = FriendStatusType.Ignore;
                    anotherFriend.StatusType = FriendStatusType.Ignored;
                    break;
                case FriendStatusType.Ignored:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.Shield:
                    ownFriend.StatusType = FriendStatusType.Shield;
                    anotherFriend.StatusType = FriendStatusType.Shielded;
                    break;
                case FriendStatusType.Shielded:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.InBlacklist:
                    throw new Exception($"{status}：参数非法");
                case FriendStatusType.InBlacklisted:
                    throw new Exception($"{status}：参数非法");
                default:
                    break;
            }


            ownFriend.AddFriendTime = DateTime.Now;
            friends.Add(ownFriend);
            friends.Add(anotherFriend);
            _appDbContext.DbContext.Set<Friend>().UpdateRange(friends);

            var topics = await _appDbContext.DbContext.Set<Topic>()
                .Where(x => x.Type == TopicType.ChatMessageNotify
                || x.Type == TopicType.FriendOnlineNotify
                || x.Type == TopicType.FriendOfflineNotify)
                .ToListAsync();

            if (topics != null && topics.Count > 0)
            {
                var userTopics = await _appDbContext.DbContext.Set<UserTopic>()
                .Where(x =>
                friends.Select(s => s.UserId).Contains(x.UserId) &&
                topics.Select(t => t.Id).Contains(x.TopicId))
                .ToListAsync();

                foreach (var userTopic in userTopics)
                {
                    userTopic.IsUnsubscribe = false;
                    userTopic.IsUnpublish = false;
                    _appDbContext.DbContext.Set<UserTopic>().Update(userTopic);
                }
            }

            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 获取我的好友列表
        /// </summary>
        /// <param name="search"></param>
        /// <returns></returns>
        public async Task<List<MyFriend>> GetMyFriendsAsync(string search) 
        {
            var currentUser = await _imUserManager.GetCurrentUserAsync();

            var query =  _appDbContext.DbContext.Set<Friend>()
                .Where(x => (x.StatusType == FriendStatusType.Agreed
                || x.StatusType == FriendStatusType.Agreed)
                && x.UserId == currentUser.Id);
            if (search.IsNullOrEmpty())
            {
                query = query.Where(x=> search.Contains(x.Remarks));
            }

            var friends = await query.ToListAsync();
            if (friends == null || friends.Count == 0)
                return new List<MyFriend>();

            var myFriends = friends.Select(x => new MyFriend
            {
                FriendId = x.Id,
                UserId = x.AnotherId,
                Remarks = x.Remarks,
                AddFriendTime = x.AddFriendTime
            }).ToList();

            var users = await _appDbContext.DbContext.Set<User>()
                .Where(x => myFriends.Select(s => s.UserId).Contains(x.Id))
                .ToListAsync();

            var userTopics = await _appDbContext.DbContext.Set<UserTopic>()
                .Where(x => myFriends.Select(s => s.FriendId).ToList().Contains((int)x.FriendId))
                .ToListAsync();

            foreach (var item in myFriends)
            {
                var user = users?
                    .Where(x => x.Id == item.UserId)
                    .FirstOrDefault();
                var contactTopics = userTopics?
                    .Where(x => x.FriendId == item.FriendId)
                    .Select(s => new ContactTopic
                    {
                        Publish = s.Publish,
                        Subscribe = s.Subscribe,
                        IsUnpublish = s.IsUnpublish,
                        IsUnsubscribe = s.IsUnsubscribe,
                    }).ToList();

                item.NickName = user.NickName;
                item.UserName = user.UserName;
                item.Name = user.Name;
                item.Email = user.Email;
                item.Birthday = user.Birthday;
                item.Sex = user.Sex;
                item.Profile = user.Profile;
                item.Avatar = user.Avatar;
                item.Signature = user.Signature;
                item.Telephone = user.Telephone;
                item.Hobby = user.Hobby;
                item.Vocation = user.Vocation;
                item.IsOnline = user.IsOnline;
                item.ContactTopics = contactTopics;
            }

            return myFriends;
        }

        /// <summary>
        /// 保存聊天信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> SaveMessageAsync(MessageModel model) 
        {
            var friendToken = "";
            var friendSenderId = model.FriendSenderId.ToString();
            var value = await _redis.StringGetAsync(friendSenderId);
            if (value.IsNullOrEmpty)
            {
                friendToken = await _appDbContext.DbContext.Set<Friend>()
               .Where(x => x.Id == model.FriendSenderId)
               .Select(s => s.Token)
               .SingleOrDefaultAsync();

                if (friendToken.IsNullOrEmpty())
                    return false;

                await _imUserManager.SaveAsync(friendSenderId, friendToken, null, false);
            }
            else
            {
                friendToken = value.ToString();
            }

            var latestMessages = await _appDbContext.DbContext.Set<Message>()
                .Where(x => x.FriendToken == friendToken && x.IsLatest == true)
                .ToListAsync();
            Message message = new Message();
            message.SetLatestMessage(latestMessages);
            _appDbContext.DbContext.Set<Message>().UpdateRange(latestMessages);

            message.AddMessage(model.FriendSenderId, model.FriendReceiverId, friendToken, model.SendTime, model.Type, model.ContentBody);         
            await _appDbContext.DbContext.Set<Message>().AddAsync(message);

            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 修改消息为已读状态
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<bool> UpdateMessageByReadAsync(int Id) 
        {
            var userId = _imUserManager.GetCurrentUserId();
            var message = await _appDbContext.DbContext.Set<Message>().SingleOrDefaultAsync(x => 
            x.Id == Id && 
            x.IsRead == false && (x.FriendReceiver.UserId == userId || x.FriendReceiver.UserId == userId));
            if (message == null) 
                return true;

            _appDbContext.DbContext.Set<Message>().Update(message.SetIsRead());
            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 删除一条消息
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<bool> DeleteSingleMessageByIdAsync(int Id) 
        {
            var userId = _imUserManager.GetCurrentUserId();
            var message = await _appDbContext.DbContext.Set<Message>().SingleOrDefaultAsync(x => 
            x.Id == Id 
            && (x.FriendSenderId == userId 
            ||  x.FriendReceiver.UserId == userId));
            if (message == null)
                throw new Exception("删除失败！消息不存在");

            await _appDbContext.DbContext.Set<Recycled>().AddAsync(new Recycled
            {
                MessageId = Id,
                UserId = userId,
                Type = RecycledType.Delete
            });
            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 清空所有消息
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<bool> ClearAllMessageByIdAsync(int friendSenderId) 
        {
            var userId = _imUserManager.GetCurrentUserId();
            var message = await _appDbContext.DbContext.Set<Message>().SingleOrDefaultAsync(x =>
              (x.FriendSenderId == friendSenderId
            || x.FriendReceiver.UserId == userId));
            if (message == null)
                throw new Exception("删除失败！消息不存在");

            var messageIds = await _appDbContext.DbContext.Set<Message>()
            .Where(x => x.FriendToken == message.FriendToken)
            .Select(s => s.Id)
            .ToListAsync();

            List<Recycled> recycleds = new List<Recycled>();
            foreach (var item in messageIds)
            {
                Recycled recycled = new Recycled
                {
                    MessageId = item,
                    UserId = userId,
                    Type = RecycledType.Delete
                };
                recycleds.Add(recycled);
            }

            await _appDbContext.DbContext.Set<Recycled>().AddRangeAsync(recycleds);
            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 撤回一条消息
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<bool> RecallMessageAsync(int Id) 
        {
            var userId = _imUserManager.GetCurrentUserId();
            var message = await _appDbContext.DbContext.Set<Message>().SingleOrDefaultAsync(x =>
            x.Id == Id
            && (x.FriendReceiver.UserId == userId
            || x.FriendReceiver.UserId == userId));
            if (message == null)
                throw new Exception("删除失败！消息不存在");

            await _appDbContext.DbContext.Set<Recycled>().AddAsync(new Recycled
            {
                MessageId = Id,
                UserId = userId,
                Type = RecycledType.Withdraw
            });
            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 找回历史消息
        /// </summary>
        /// <param name="friendSenderId"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public async Task<bool> RetrieveHistoryMessageAsync(int friendSenderId, DateTime startTime, DateTime endTime) 
        {
            var userId = _imUserManager.GetCurrentUserId();
            var message = await _appDbContext.DbContext.Set<Message>().SingleOrDefaultAsync(x =>
               x.FriendSenderId == userId || 
               x.FriendReceiver.UserId == userId);
            if (message == null)
                throw new Exception("消息不存在");

            var messageIds = await _appDbContext.DbContext.Set<Message>()
            .Where(x => x.FriendToken == message.FriendToken
            && x.ReceiveTime >= startTime && x.ReceiveTime <= endTime)
            .Select(s => s.Id)
            .ToListAsync();
            if (messageIds == null || messageIds.Count == 0)
                throw new Exception("消息不存在");

            var recycledMessages = await _appDbContext.DbContext.Set<Recycled>()
            .Where(x => x.UserId == userId && messageIds.Contains(x.MessageId))
            .ToListAsync();
            if (recycledMessages == null || recycledMessages.Count == 0)
                throw new Exception("消息不存在");

            _appDbContext.DbContext.Set<Recycled>().RemoveRange(recycledMessages);

            return (await _appDbContext.DbContext.SaveChangesAsync()) > 0;
        }

        /// <summary>
        /// 获取历史聊天信息
        /// </summary>
        public async Task<List<HistoryMessage>> GetHistoryMessageAsync()
        {
            var user = await _imUserManager.GetCurrentUserAsync();
            var friend = await _appDbContext.DbContext.Set<Friend>()
            .Where(x => x.UserId == user.Id)
            .Select(s => new
            {
                s.Id,
                s.Token,
                s.Another.UserName,
                s.Another.NickName,
                s.Another.Avatar
            }).SingleOrDefaultAsync();
            if (friend == null)
                return new List<HistoryMessage>();

            var messages = await _appDbContext.DbContext.Set<Message>()
            .Where(x => x.FriendToken == friend.Token)
            .Select(s => new HistoryMessage
            {
                Id = s.Id,
                FriendSenderId = s.FriendSenderId,
                FriendReceiverId = s.FriendReceiverId,
                SendTime = s.SendTime,
                ContentBody = s.ContentBody,
                Type = s.Type,
                RecycledType = RecycledType.None
            }).ToListAsync();

            if (messages == null || messages.Count == 0)
                return new List<HistoryMessage>();

            var recycledMessages = await _appDbContext.DbContext.Set<Recycled>()
            .Where(x => x.UserId == user.Id && messages.Select(s => s.Id).Contains(x.Id))
            .ToListAsync();

            foreach (var item in recycledMessages) 
            {
                messages.FirstOrDefault(x => x.Id == item.Id).RecycledType = item.Type;
            }
               
            foreach (var message in messages)
            {
                message.ReceiverUserName = friend.UserName;
                message.ReceiverNickName = friend.NickName;
                message.ReceiverAvatar = friend.Avatar;
                message.SenderNickName = user.NickName;
                message.SenderUserName = user.UserName;
                message.SenderAvatar = user.Avatar;
            }

            return messages;
        }

        /// <summary>
        /// 生成Topic数据
        /// </summary>
        public void GenerateTopicSeedData()
        {
            var count = _appDbContext.DbContext.Set<Topic>().Count();
            if (count > 0)
            {
                return;
            }

            List<Topic> topics = new List<Topic>()
            {
                new Topic(){ Id=1, Type=TopicType.SystemAllNotify, Remark="系统所有消息通知",SubscribeFormat="system/notify/all",PublishFormat="", IsDefault =true   },
                new Topic(){ Id=2, Type=TopicType.FriendAddNotify, Remark="好友添加通知" ,SubscribeFormat="client/notify/buddy/+/add/{client_id_oneself}",PublishFormat="client/notify/buddy/{client_id_oneself}/add/{client_id_others}", IsDefault = true    },
                new Topic(){ Id=3, Type=TopicType.ChatMessageNotify , Remark="聊天消息通知",SubscribeFormat="client/chat/from/{client_id_others}/to/{client_id_oneself}",PublishFormat="client/chat/from/{client_id_oneself}/to/{client_id_others}" , IsDefault =false   },
                //new Topic(){ Id=4, Type=TopicType.GroupVerifyNotify, Remark="群验证通知" ,SubscribeFormat="",PublishFormat=""  },
                //new Topic(){ Id=5, Type=TopicType.RemoveGroupNotify, Remark="移除群聊通知"  ,SubscribeFormat="client/chats/room/{room_id}/remove/to/{client_id_oneself}",PublishFormat="" },
                new Topic(){ Id=6, Type=TopicType.FriendOnlineNotify, Remark="好友上线通知"  ,SubscribeFormat="client/notify/friend/online/from/+/to/{client_id_oneself}",PublishFormat="client/notify/friend/online/from/{client_id_oneself}/to/{client_id_others}"  , IsDefault =false },
                new Topic(){ Id=7, Type=TopicType.FriendOfflineNotify, Remark="好友下线通知" ,SubscribeFormat="client/notify/friend/offline/from/+/to/{client_id_oneself}",PublishFormat="client/notify/friend/offline/from/{client_id_oneself}/to/{client_id_others}"  , IsDefault =false  },
                //new Topic(){ Id=8, Type=TopicType.GroupFriendOnlineNotify, Remark="群友上线通知"  ,SubscribeFormat="client/notify/room/online/from/+/to/{client_id_oneself}",PublishFormat="" },
                //new Topic(){ Id=9, Type=TopicType.GroupFriendOfflineNotify , Remark="群友下线通知" ,SubscribeFormat="",PublishFormat="" },
                new Topic(){ Id=10, Type=TopicType.FriendAgreeNotify , Remark="好友同意通知" ,SubscribeFormat="client/notify/buddy/+/agree/with/{client_id_oneself}",PublishFormat="client/notify/buddy/{client_id_others}/agree/with/{client_id_oneself}" , IsDefault =true   },
                new Topic(){ Id=11, Type=TopicType.FriendDisagreeNotify, Remark="好友不同意通知" ,SubscribeFormat="client/notify/buddy/+/disagree/with/{client_id_oneself}",PublishFormat="client/notify/buddy/{client_id_oneself}/disagree/with/{client_id_others}" , IsDefault =true   },
            };

            _appDbContext.DbContext.Set<Topic>().AddRange(topics);
            _appDbContext.DbContext.SaveChanges();
        }
    }
}
